/*
 * This class is to serve as the outline of the state for the StateMachine.
 */
package edu.wpi.first.wpilibj.templates.assets.statemachine;

import edu.wpi.first.wpilibj.Timer;

/**
 *
 * @author Jarrod Risley
 * 
 * Every state that is to be used by the StateMachine must use extend this 
 * class.
 */
public abstract class State {
    
    /*
     * Global Interface Variables
     */
     private State nextState;
     private State previousState;
     
     private String stateName;
     
     private boolean isFinished = false;
     private boolean isInterruptible = true;
     
     private double startTime;
     private double timeoutTime;
     
     
     // CONSTRUCTOR //
     
     
     protected State(String name) {
         
         stateName = name;
         
     } // end State Constructor
     
     
     // METHODS //
     
     /**
      * Code that runs just before a state runs.
      */
     protected abstract void runFirst();
     
     /**
      * Code that runs every time a state runs.
      */
     protected abstract void run();
     
     /**
      * Code that ends just before the state exits.
      */
     protected abstract void runLast();
     
     /**
      * Check to see if the state has finished its job.
      * 
      * @return True if the state has finished.
      */
     protected abstract boolean isFinished();
     
     /**
      * Ends the state.
      */
     protected abstract void end();
    
     /**
      * Gets an instance of the State and chains it up to another one.
      * @param nextState The nextState to chain up to.
      * @return The State's static instance.
      */
     protected abstract State getChainedInstance(State nextState);
     
     /**
      * Gets the previous state.
      * 
      * @return The state before this one.
      */
     protected final State getLast() {
         return previousState;
     } // end getLast
     
     /**
      * Gets the next state.
      * 
      * @return The next state in line.
      */
     protected final State getNext() {
         return nextState;
     } // end getNext
     
     /**
      * Sets the next state for chaining.
      * @param state The next state to chain to.
      */
     protected final void setNext(State state) {
         nextState = state;
     } // end setNext
     
     /**
      * Sets the field isFinished to true so that the state may end.
      */
     protected final void setFinished() {
         isFinished = true;
     } // end setFinished
     
     /**
      * Gets the field isFinished.
      * @return 
      */
     public final boolean getFinished() {
         return isFinished;
     } // end getFinished
     
     /**
      * Resets the isFinished flag so that the command can rerun!
      */
     protected final void resetState() {
         isFinished = false;
     } // end resetState
     
     /**
      * Sets this state to the last state to run.
      */
     protected final void setSelfToLastState() {
         previousState = this;
     } // end setSelfToLastState
     
     /**
      * Sets the time for the state to time out.
      * @param time How many seconds before the state times out.
      */
     protected final void setTimeoutTimer(double time) {
         timeoutTime = Timer.getFPGATimestamp() + time;
     } // end setTimeoutTimter
     
     /**
      * Checks to see if the state has timed out.
      * 
      * @return True if timed out.
      */
     protected final boolean isTimedOut() {
         
         if (Timer.getFPGATimestamp() >= timeoutTime)
             return true;
         
         return false;
         
     } // end isTimedOut
     
     /**
      * Sets a state to be interruptible or not.
      * @param interrupt Set to false if you want this state to run until its
      * finishing conditions are met.
      */
     protected final void setInterruptible(boolean interrupt) {
         isInterruptible = interrupt;
     } // end setInterruptable
     
     /**
      * Is this state interruptible or not?
      * @return True if this state can be interrupted.
      */
     protected final boolean isInterruptible() {
         return isInterruptible;
     } // end isInterruptible
     
} // end State
